/*
 * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package java.io;

import java.io.InputStream;
import java.util.Enumeration;
import java.util.Vector;

/**
 * SequenceInputStream表示其他inputstream的逻辑连接。
 * 它从一个有序的输入流集合开始，从第一个开始读取，直到到达文件末尾，
 * 然后从第二个开始读取，以此类推，直到到达所包含的最后一个输入流的文件末尾。
 *
 * @author  Author van Hoff
 * @since   JDK1.0
 */
public
class SequenceInputStream extends InputStream {
	
	// 内部的Enumeration，可以不断调用它的nextElement方法
    Enumeration<? extends InputStream> e;
    
    // 当前读取的输入流
    InputStream in;

    /**
     * 通过记住参数来初始化新创建的SequenceInputStream，
     * 该参数必须是一个Enumeration，生成对象的运行时类型为InputStream。
     * 枚举产生的输入流将被有序地读取，以提供要从这个SequenceInputStream读取的字节。
     * 在枚举的每个输入流被耗尽后，将通过调用其close方法关闭它。
     *
     * @param   e   an enumeration of input streams.
     * @see     java.util.Enumeration
     */
    public SequenceInputStream(Enumeration<? extends InputStream> e) {
        this.e = e;
        try {
        	// in为e的下一个流
            nextStream();
        } catch (IOException ex) {
            // This should never happen
            throw new Error("panic");
        }
    }

    /**
     * 通过记住两个参数(首先是s1，然后是s2)
     * 来初始化一个新创建的SequenceInputStream，
     * 以提供要从这个SequenceInputStream读取的字节。
     *
     * @param   s1   the first input stream to read.
     * @param   s2   the second input stream to read.
     */
    public SequenceInputStream(InputStream s1, InputStream s2) {
        Vector<InputStream> v = new Vector<>(2);

        v.addElement(s1);
        v.addElement(s2);
        e = v.elements();
        // 创建一个e给它
        try {
            nextStream();
        } catch (IOException ex) {
            // This should never happen
            throw new Error("panic");
        }
    }

    /**
     *  如果到达EOF，则继续在下一个流中读取。
     */
    final void nextStream() throws IOException {
    	// 如果当前的流不为null，关闭当前的流
        if (in != null) {
            in.close();
        }
        
        // in变成e的下一个元素，如果没有，为null
        if (e.hasMoreElements()) {
            in = (InputStream) e.nextElement();
            if (in == null)
                throw new NullPointerException();
        }
        else in = null;

    }

    /**
     * 返回可以从当前依赖的输入流读取(或跳过)的字节数的估计数，
     * 而不会被当前依赖的输入流的方法的下一次调用阻塞。
     * 下一个调用可能是同一个线程或另一个线程。
     * 单个读取或跳过这许多字节不会阻塞，但可能读取或跳过更少的字节。
     * 此方法只是调用当前依赖的输入流的available方法并返回结果。
     *
     * @return an estimate of the number of bytes that can be read (or
     *         skipped over) from the current underlying input stream
     *         without blocking or {@code 0} if this input stream
     *         has been closed by invoking its {@link #close()} method
     * @exception  IOException  if an I/O error occurs.
     *
     * @since   JDK1.1
     */
    public int available() throws IOException {
        if (in == null) {
            return 0; // no way to signal EOF from available()
        }
        return in.available();
    }

    /**
     * 从这个输入流中读取下一个字节的数据。
     * 字节作为0到255之间的int类型返回。
     * 如果由于到达流的末尾而没有可用的字节，则返回-1值。
     * 此方法将一直阻塞，直到输入数据可用、检测到流的末尾或抛出异常为止。
     * <p>
     * 该方法尝试从当前子流中读取一个字符。
     * 如果它到达流的末尾，它将调用当前子流的close方法并开始从下一个子流读取。
     *
     * @return     the next byte of data, or <code>-1</code> if the end of the
     *             stream is reached.
     * @exception  IOException  if an I/O error occurs.
     */
    public int read() throws IOException {
        while (in != null) {
            int c = in.read();
            if (c != -1) {
                return c;
            }
            nextStream();
        }
        // 不会返回-1，知道所有流都被读完
        return -1;
    }

    /**
     * 从这个输入中读取最多len字节的数据流到一个字节数组。
     * 如果len不为零，该方法将阻塞，直到至少有1个字节的输入可用;
     * 否则，什么字节都不读取并返回0。
     * <p>
     * SequenceInputStream的read方法尝试从当前子流中读取数据。
     * 如果由于子流已经到达流的末尾而无法读取任何字符，
     * 则调用当前子流的close方法，并从下一个子流开始读取。
     *
     * @param      b     the buffer into which the data is read.
     * @param      off   the start offset in array <code>b</code>
     *                   at which the data is written.
     * @param      len   the maximum number of bytes read.
     * @return     int   the number of bytes read.
     * @exception  NullPointerException If <code>b</code> is <code>null</code>.
     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
     * <code>len</code> is negative, or <code>len</code> is greater than
     * <code>b.length - off</code>
     * @exception  IOException  if an I/O error occurs.
     */
    public int read(byte b[], int off, int len) throws IOException {
        if (in == null) {
            return -1;
        } else if (b == null) {
            throw new NullPointerException();
        } else if (off < 0 || len < 0 || len > b.length - off) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return 0;
        }
        do {
        	// 从当前的in读取，如果为0，则下一个流
            int n = in.read(b, off, len);
            if (n > 0) {
                return n;
            }
            nextStream();
        } while (in != null);
        return -1;
    }

    /**
     * 关闭该输入流并释放与该流关联的任何系统资源。
     * 已关闭的SequenceInputStream不能执行输入操作，也不能重新打开。
     * <p>
     * 如果该流是从enumeration创建的，
     * 则从枚举请求所有剩余的元素，并在close方法返回之前关闭。
     *
     * @exception  IOException  if an I/O error occurs.
     */
    public void close() throws IOException {
        do {
        	// 不断关闭当前流，并下一个
            nextStream();
        } while (in != null);
    }
}
